package com.weilele.mvvm.base.helper


import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.*
import androidx.viewbinding.ViewBinding
import com.weilele.mvvm.utils.vLaout.MvvmHolder
import com.weilele.mvvm.utils.safeGet
import java.lang.IllegalArgumentException
import java.lang.NullPointerException
import java.lang.reflect.ParameterizedType


/**
 * 创建viewModel
 */
inline fun <reified T : ViewModel> ViewModelStoreOwner.getViewModel(): T {
    return ViewModelProvider(this).get(T::class.java)
}

/**
 * activity的viewModel
 */
inline fun <reified T : ViewModel> Fragment.getActivityViewModel(): T {
    return activity?.getViewModel()
            ?: throw NullPointerException(
                    if (activity == null) "activity is null"
                    else "activity ViewModel not find ${T::class.java.simpleName}"
            )
}

/**
 * 在activity或者faragment创建Binding
 */
fun <Binding : ViewBinding?> Any.createViewBinding(
        inflater: LayoutInflater, cls: Class<Binding>? = null, parent: ViewGroup? = null,
        attach: Boolean = false, position: Int = 0
): Binding? {
    val type = cls ?: javaClass.getParameterizedType()
            ?.actualTypeArguments?.get(position)
    if (type == ViewBinding::class.java) {
        return null
    }
    return type.safeGet<Class<Binding>>()?.createViewBindingInstance(inflater, parent, attach)
}

/**
 * 通过binding类反射创建binding对象
 */
fun <Binding : ViewBinding?> Class<Binding>.createViewBindingInstance(
        inflater: LayoutInflater,
        parent: ViewGroup? = null,
        attach: Boolean = false,
): Binding? {
    return ignoreError {
        this.getMethod(
                "inflate",
                LayoutInflater::class.java,
                ViewGroup::class.java,
                Boolean::class.java
        ).invoke(null, inflater, parent, attach) as? Binding?
    }
}

/**
 * 通过viewHolder类创建ViewHolder对象
 */
fun <Holder : MvvmHolder<*, *>> Class<Holder>.createHolderInstance(
        inflater: LayoutInflater,
        parent: ViewGroup? = null,
        attach: Boolean = false,
): Holder {
    val binding = this.getParameterizedType()
            ?.actualTypeArguments?.get(1)
            ?.safeGet<Class<ViewBinding>>()
            ?.createViewBindingInstance(inflater, parent, attach)
            ?: throw IllegalArgumentException("通过viewHolder类（${this.name}）创建ViewHolder对象失败")
    return this.getConstructor(binding::class.java).newInstance(binding) as Holder
}

/**
 * 将class转为ParameterizedType，方便获取此类的类泛型
 */
fun Class<*>?.getParameterizedType(): ParameterizedType? {
    if (this == null) {
        return null
    }
    val type = this.genericSuperclass
    return if (type == null || type !is ParameterizedType) {
        this.superclass.getParameterizedType()
    } else {
        type
    }
}

/**
 * 父fragment的viewModel
 */
inline fun <reified T : ViewModel> Fragment.getParentFragmentViewModel(): T {
    return parentFragment?.getViewModel()
            ?: throw NullPointerException(
                    if (parentFragment == null) "parentFragment is null"
                    else "parentFragment ViewModel not find ${T::class.java.simpleName}"
            )
}


/**
 * 将LiveBean包装，使注册更简单
 */
sealed class LiveDataWrap {

    abstract fun observer(lifecycle: LifecycleOwner)
    abstract fun observeForever()
    abstract fun removeObserve()

    data class WrapLiveData<T>(
            val liveData: LiveData<T>,
            inline val call: T.() -> Unit,
            val observers: MutableList<Observer<T>> = mutableListOf()
    ) : LiveDataWrap() {
        override fun observer(lifecycle: LifecycleOwner) {
            observers.add(lifecycle.observerLiveData(liveData, call))
        }

        override fun observeForever() {
            observers.add(liveData.observeForeverLiveData(call))
        }

        override fun removeObserve() {
            observers.forEach {
                liveData.removeObserver(it)
            }
            observers.clear()
        }
    }

    data class WrapOnlySuccessLiveData<T>(
            val liveData: LiveData<StatusValue<T>>,
            inline val call: T.() -> Unit,
            val observers: MutableList<Observer<StatusValue<T>>> = mutableListOf()
    ) : LiveDataWrap() {
        override fun observer(lifecycle: LifecycleOwner) {
            observers.add(lifecycle.observerLiveDataSuccess(liveData, call))
        }

        override fun observeForever() {
            observers.add(liveData.observerForeverLiveDataSuccess(call))
        }

        override fun removeObserve() {
            observers.forEach {
                liveData.removeObserver(it)
            }
            observers.clear()
        }
    }
}

/**
 * 注册
 */
fun List<LiveDataWrap>?.observer(lifecycle: LifecycleOwner) {
    this?.forEach {
        it.observer(lifecycle)
    }
}

fun List<LiveDataWrap>?.observeForever() {
    this?.forEach {
        it.observeForever()
    }
}

fun MutableList<LiveDataWrap>?.removeObserver() {
    this?.forEach {
        it.removeObserve()
    }
    this?.clear()
}


/**
 * 提供方法去创建
 */
infix fun <T> LiveData<T>.wrapObserver(call: (T) -> Unit): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call)
}

inline fun <T1, T> LiveData<T>.wrapObserver(t1: T1, crossinline call: Function2<T1, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, this)
    })
}

inline fun <T1, T2, T> LiveData<T>.wrapObserver(t1: T1, t2: T2, crossinline call: Function3<T1, T2, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, t2, this)
    })
}

inline fun <T1, T2, T3, T> LiveData<T>.wrapObserver(t1: T1, t2: T2, t3: T3,
                                                    crossinline call: Function4<T1, T2, T3, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, t2, t3, this)
    })
}

inline fun <T1, T2, T3, T4, T> LiveData<T>.wrapObserver(t1: T1, t2: T2, t3: T3, t4: T4,
                                                        crossinline call: Function5<T1, T2, T3, T4, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T> LiveData<T>.wrapObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5,
                                                            crossinline call: Function6<T1, T2, T3, T4, T5, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T6, T> LiveData<T>.wrapObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6,
                                                                crossinline call: Function7<T1, T2, T3, T4, T5, T6, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, t6, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T6, T7, T> LiveData<T>.wrapObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7,
                                                                    crossinline call: Function8<T1, T2, T3, T4, T5, T6, T7, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, t6, t7, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T6, T7, T8, T> LiveData<T>.wrapObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8,
                                                                        crossinline call: Function9<T1, T2, T3, T4, T5, T6, T7, T8, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, t6, t7, t8, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, T> LiveData<T>.wrapObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9,
                                                                            crossinline call: Function10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, this)
    })
}

/**
 * 提供方法去创建
 */
infix fun <T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(call: (T) -> Unit): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call)
}

inline fun <T1, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, crossinline call: Function2<T1, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, this)
    })
}

inline fun <T1, T2, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, t2: T2, crossinline call: Function3<T1, T2, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, t2, this)
    })
}

inline fun <T1, T2, T3, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, t2: T2, t3: T3,
                                                                            crossinline call: Function4<T1, T2, T3, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, t2, t3, this)
    })
}

inline fun <T1, T2, T3, T4, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, t2: T2, t3: T3, t4: T4,
                                                                                crossinline call: Function5<T1, T2, T3, T4, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5,
                                                                                    crossinline call: Function6<T1, T2, T3, T4, T5, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T6, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6,
                                                                                        crossinline call: Function7<T1, T2, T3, T4, T5, T6, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, t6, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T6, T7, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7,
                                                                                            crossinline call: Function8<T1, T2, T3, T4, T5, T6, T7, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, t6, t7, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T6, T7, T8, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8,
                                                                                                crossinline call: Function9<T1, T2, T3, T4, T5, T6, T7, T8, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, t6, t7, t8, this)
    })
}

inline fun <T1, T2, T3, T4, T5, T6, T7, T8, T9, T> LiveData<StatusValue<T>>.wrapOnlySuccessObserver(t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6, t7: T7, t8: T8, t9: T9,
                                                                                                    crossinline call: Function10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T, Unit>): LiveDataWrap {
    return LiveDataWrap.WrapOnlySuccessLiveData(this, call = {
        call.invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, this)
    })
}